package com.tonann.app.task;

import com.tonann.app.conf.AsyncService;
import com.tonann.app.conf.AsyncServiceImpl;
import com.tonann.app.conf.ConvertHandler;
import com.tonann.app.domain.AppSensorRecord;
import com.tonann.app.domain.AppSensorRecordDay;
import com.tonann.app.domain.AppSensorRecordHour;
import com.tonann.app.domain.AppSensorRecordMonth;
import com.tonann.app.mapper.AppSensorRecordDayMapper;
import com.tonann.app.mapper.AppSensorRecordHourMapper;
import com.tonann.app.mapper.AppSensorRecordMapper;
import com.tonann.app.mapper.AppSensorRecordMonthMapper;
import com.tonann.app.service.IAppSensorRecordService;
import com.tonann.app.service.IAppSensorService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 楚秀接口
 *
 * @author c-sunshuai
 */
@Slf4j
@Service
public class DataCollectionTask {

    @Resource
    private IAppSensorService appSensorService;
    @Resource
    private AppSensorRecordHourMapper recordHoursMapper;
    @Resource
    private AppSensorRecordDayMapper recordDayMapper;
    @Resource
    private AppSensorRecordMonthMapper recordMonthMapper;

    @Resource
    private AppSensorRecordMapper recordMapper;
    @Resource
    private IAppSensorRecordService appSensorRecordService;

    public void dataCollection() {
        log.info("开始执行数据归集任务开始");
//        List<AppSensor> sensorList = appSensorService.selectAppSensorAllPureList(new AppSensor());
//        List<Long> sensorIdList = sensorList.stream().map(AppSensor::getSensorId).collect(Collectors.toList());
        List<Long> sensorIdList = recordMapper.selectSensorIdList();
        List<List<Long>> sensorIds = ConvertHandler.splitList(sensorIdList, 500);
        int index = 1;
        for (List<Long> ids : sensorIds) {
            log.info("查询传感器记录第" + index + "次，" + "共" + sensorIds.size() + "次");
            index++;
            log.info("所有记录开始");
            List<AppSensorRecord> appSensorRecordALLList = recordMapper.selectAppSensorRecordBySensorIds(ids);
            Map<Long, List<AppSensorRecord>> sensorRecordAllMap = appSensorRecordALLList.stream().collect(Collectors.groupingBy(AppSensorRecord::getSensorId));
            Map<Long, Map<LocalDateTime, List<AppSensorRecord>>> recordMap = sensorRecordAllMap.keySet().stream().collect(Collectors.toMap(item -> item, it -> {
                List<AppSensorRecord> recordList = sensorRecordAllMap.get(it);
                return recordList.stream().collect(Collectors.groupingBy(e -> e.getCreateTime().toLocalDate().atStartOfDay().plusHours(e.getCreateTime().getHour())));
            }));
            log.info("所有记录结束");
            log.info("按时记录查询开始");
            List<AppSensorRecordHour> appSensorRecordHourList = recordHoursMapper.selectAppSensorRecordBySensorIds(ids);
            List<AppSensorRecordDay> appSensorRecordDayList = recordDayMapper.selectAppSensorRecordBySensorIds(ids);
            List<AppSensorRecordMonth> appSensorRecordMonthList = recordMonthMapper.selectAppSensorRecordBySensorIds(ids);
            log.info("按时记录查询结束");
            log.info("按时记录处理开始");
            Map<Long, List<AppSensorRecordHour>> recordHoursMap = appSensorRecordHourList.stream().collect(Collectors.groupingBy(AppSensorRecordHour::getSensorId));
            Map<Long, Map<LocalDateTime, List<AppSensorRecordHour>>> recordHoursMap1 = recordHoursMap.keySet().stream().collect(Collectors.toMap(item -> item, it -> {
                List<AppSensorRecordHour> hourList = recordHoursMap.get(it);
                return hourList.stream().collect(Collectors.groupingBy(e -> e.getCreateTime().toLocalDate().atStartOfDay().plusHours(e.getCreateTime().getHour())));
            }));
            Map<Long, List<AppSensorRecordDay>> recordDayMap = appSensorRecordDayList.stream().collect(Collectors.groupingBy(AppSensorRecordDay::getSensorId));
            Map<Long, Map<LocalDate, List<AppSensorRecordDay>>> recordDayMap1 = recordDayMap.keySet().stream().collect(Collectors.toMap(item -> item, it -> {
                List<AppSensorRecordDay> dayList = recordDayMap.get(it);
                return dayList.stream().collect(Collectors.groupingBy(AppSensorRecordDay::getCreateTime));
            }));
            Map<Long, List<AppSensorRecordMonth>> recordMonthMap = appSensorRecordMonthList.stream().collect(Collectors.groupingBy(AppSensorRecordMonth::getSensorId));
            Map<Long, Map<LocalDate, List<AppSensorRecordMonth>>> recordMonthMap1 = recordDayMap.keySet().stream().collect(Collectors.toMap(item -> item, it -> {
                List<AppSensorRecordMonth> monthList = recordMonthMap.get(it);
                return monthList.stream().collect(Collectors.groupingBy(AppSensorRecordMonth::getCreateTime));
            }));
            log.info("按时记录处理结束");
            List<AppSensorRecordHour> recordHoursList = new ArrayList<>();
            List<AppSensorRecordDay> recordDayList = new ArrayList<>();
            List<AppSensorRecordMonth> recordMonthList = new ArrayList<>();
            //首先处理同一个时间点有多个数据的情况
            for (Long sensorId : sensorRecordAllMap.keySet()) {
                Map<LocalDateTime, List<AppSensorRecord>> dateMap = recordMap.get(sensorId);
                if (dateMap != null) {
                    //处理小时数据
                    Map<LocalDateTime, List<AppSensorRecordHour>> hoursMap = recordHoursMap1.get(sensorId);
                    Set<LocalDateTime> hoursTimeSet = dateMap.keySet();
                    if (hoursMap != null) {
                        Set<List<AppSensorRecordHour>> hoursSet = hoursMap.values().stream().filter(list -> list.size() > 1).collect(Collectors.toSet());
                        hoursSet.forEach(list -> {
                            if (list.size() > 1) {
                                list.remove(0);
                                recordHoursMapper.deleteAppSensorRecordHourByRecordIds(list.stream().map(AppSensorRecordHour::getRecordId).toArray(Long[]::new));
                            }
                        });
                        hoursTimeSet = hoursTimeSet.stream().filter(item -> !hoursMap.containsKey(item)).collect(Collectors.toSet());
                    }
                    List<AppSensorRecordHour> recordHoursSensorList = new ArrayList<>();
                    for (LocalDateTime dateTime : hoursTimeSet) {
                        Optional<BigDecimal> maxOptional = dateMap.get(dateTime).stream().map(AppSensorRecord::getValue).map(BigDecimal::new).max(BigDecimal::compareTo);
                        if (maxOptional.isPresent()) {
                            AppSensorRecord record = dateMap.get(dateTime).get(0);
                            BigDecimal max = maxOptional.get();
                            AppSensorRecordHour hours = new AppSensorRecordHour();
                            hours.setSensorId(record.getSensorId());
                            hours.setValue(max.toString());
                            hours.setCreateTime(dateTime);
                            recordHoursSensorList.add(hours);
                        }
                    }
                    //处理天数据
                    Map<LocalDate, List<AppSensorRecordDay>> dayMap = recordDayMap1.get(sensorId);
                    if (dayMap != null) {
                        Set<List<AppSensorRecordDay>> daySet = dayMap.values().stream().filter(list -> list.size() > 1).collect(Collectors.toSet());
                        daySet.forEach(list -> {
                            list.remove(0);
                            recordDayMapper.deleteAppSensorRecordDayByRecordIds(list.stream().map(AppSensorRecordDay::getRecordId).toArray(Long[]::new));
                        });
                    }
                    if (!recordHoursSensorList.isEmpty()) {
                        recordHoursList.addAll(recordHoursSensorList);
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                        Map<LocalDate, List<AppSensorRecordHour>> hoursDayMap = recordHoursSensorList.stream().collect(Collectors.groupingBy(ldt -> LocalDate.parse(ldt.getCreateTime().format(formatter))));
                        Set<LocalDate> dateTimeSet = hoursDayMap.keySet();
                        if (dayMap != null) {
                            dateTimeSet = dateTimeSet.stream().filter(item -> !dayMap.containsKey(item)).collect(Collectors.toSet());
                            LocalDate today = LocalDate.now();
                            if (hoursDayMap.containsKey(today)&&dayMap.containsKey(today)) {
                                recordDayMapper.deleteAppSensorRecordDayByRecordIds(dayMap.get(today).stream().map(AppSensorRecordDay::getRecordId).toArray(Long[]::new));
                            }
                            if (!dateTimeSet.contains(today) && hoursDayMap.containsKey(today)) {
                                dateTimeSet.add(today);
                            }
                        }
                        List<AppSensorRecordDay> recordDaySensorList = new ArrayList<>();
                        for (LocalDate day : dateTimeSet) {
                            Optional<BigDecimal> maxOptional = hoursDayMap.get(day).stream().map(AppSensorRecordHour::getValue).filter(Objects::nonNull).map(BigDecimal::new).max(BigDecimal::compareTo);
                            if (maxOptional.isPresent()) {
                                AppSensorRecordDay recordDay = new AppSensorRecordDay();
                                recordDay.setCreateTime(day);
                                recordDay.setSensorId(sensorId);
                                BigDecimal max = maxOptional.get();
                                recordDay.setValue(max.toString());
                                recordDaySensorList.add(recordDay);
                            }
                        }
                        //处理月数据
                         Map<LocalDate, List<AppSensorRecordMonth>> monthMap = recordMonthMap1.get(sensorId);
                        if (monthMap != null) {
                            Set<List<AppSensorRecordMonth>> monthSet = monthMap.values().stream().filter(list -> list.size() > 1).collect(Collectors.toSet());
                            monthSet.forEach(list -> {
                                list.remove(0);
                                recordMonthMapper.deleteAppSensorRecordMonthByRecordIds(list.stream().map(AppSensorRecordMonth::getRecordId).toArray(Long[]::new));
                            });
                        }
                        if (!recordDaySensorList.isEmpty()) {
                            recordDayList.addAll(recordDaySensorList);
                            DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM");
                            Map<LocalDate, List<AppSensorRecordDay>> monthDayMap = recordDaySensorList.stream().collect(Collectors.groupingBy(ldt -> LocalDate.parse(ldt.getCreateTime().format(formatter1) + "-01")));
                            Set<LocalDate> monthTimeSet = monthDayMap.keySet();
                            if (monthMap != null) {
                                monthTimeSet = monthTimeSet.stream().filter(item -> !monthMap.containsKey(item)).collect(Collectors.toSet());
                                LocalDate thisMonth = LocalDate.now();
                                thisMonth = LocalDate.parse(thisMonth.format(formatter1) + "-01");
                                if (monthDayMap.containsKey(thisMonth) && monthMap.containsKey(thisMonth)) {
                                    recordMonthMapper.deleteAppSensorRecordMonthByRecordIds(monthMap.get(thisMonth).stream().map(AppSensorRecordMonth::getRecordId).toArray(Long[]::new));
                                }
                                if (!monthTimeSet.contains(thisMonth) && monthDayMap.containsKey(thisMonth)) {
                                    monthTimeSet.add(thisMonth);
                                }
                            }
                            for (LocalDate month : monthTimeSet) {
                                Optional<BigDecimal> maxOptional = monthDayMap.get(month).stream().map(AppSensorRecordDay::getValue).map(BigDecimal::new).max(BigDecimal::compareTo);
                                if (maxOptional.isPresent()) {
                                    AppSensorRecordMonth recordMonth = new AppSensorRecordMonth();
                                    recordMonth.setSensorId(sensorId);
                                    recordMonth.setCreateTime(month);
                                    BigDecimal max = maxOptional.get();
                                    recordMonth.setValue(max.toString());
                                    recordMonthList.add(recordMonth);
                                }
                            }
                        }
                    }
                }
            }
            log.info("传感器转换end");
            if (!recordHoursList.isEmpty()) {
                log.info("按小时感器插入开始");
                AsyncService<AppSensorRecordHour> asyncServiceHours = new AsyncServiceImpl<>();
                int size = asyncServiceHours.startMultiThread(recordHoursList, recordHoursMapper);
                log.info("插入小时数据：" + recordHoursList.size() + "条");
                log.info("按小时感器插入结束");
            }
            if (!recordDayList.isEmpty()) {
                AsyncService<AppSensorRecordDay> asyncServiceDay = new AsyncServiceImpl<>();
                int size = asyncServiceDay.startMultiThread(recordDayList, recordDayMapper);
                log.info("插入天数据：" + recordDayList.size() + "条");
                log.info("按日感器插入结束");
            }
            if (!recordMonthList.isEmpty()) {
                AsyncService<AppSensorRecordMonth> asyncServiceMonth = new AsyncServiceImpl<>();
                int size = asyncServiceMonth.startMultiThread(recordMonthList, recordMonthMapper);
                log.info("插入月数据：" + recordMonthList.size() + "条");
                log.info("按月感器插入结束");
            }
        }
        log.info("删除30天前的原始数据");
        appSensorRecordService.deleteAppSensorRecordBefore30Day();
        log.info("执行数据归集任务完成");
    }

}
